﻿///Code based on
/// http://snipd.net/minimax-algorithm-with-alpha-beta-pruning-in-c

using System;
using System.Diagnostics;
using System.Linq;
using Core.Models;
using Service.Logs;

namespace Service.AI
{
    public class AlphaBeta
    {
        private GameState Initial_Gs;
        private Node rootNode;
        private Node bestNode;
        private string treeVisual;
        private int maxDepth;
        private int amountNodes;
        public AlphaBeta(GameState p_gs)
        {
            Initial_Gs = p_gs;
        }

        public MovesInfo StartIteration(int depth, bool player)
        {
           // maxDepth = depth;
            amountNodes = 0;
            rootNode = new Node(Initial_Gs);
            //treeVisual = "\\\n";
            var score = Iterate(rootNode, depth, int.MinValue, int.MaxValue, player,"");
            Debug.WriteLine("******************************");
            Debug.WriteLine("Amount of nodes: " + amountNodes);
            //Logging.LogAlphaBetaTree(treeVisual);
            return bestNode.ogMove;
        }

        public double Iterate(Node node, double depth, double alpha, double beta, bool player, string indent)
        {
            amountNodes++;
            if (depth == 0)
            {
                return node.gs.GetBoardScore(Initial_Gs.WhoseMove);
            }

            var childs = node.Children();

            if (!childs.Any())
                return node.gs.GetBoardScore(Initial_Gs.WhoseMove);

            if (player)
            {
                //indent
                //if (depth != maxDepth)
                //{
                //    indent += "| ";
                //}
                foreach (Node child in childs)
                {
                    //logging

                    //double score = child.gs.GetBoardScore(Initial_Gs.WhoseMove);
                    //string move = "";
                    //if (child.currentMi != null)
                    //    move = child.currentMi.WriteFullMove();
                    //else
                    //    move = child.ogMove.WriteFullMove();

                    //treeVisual += indent + "|-A " + score + " => Move: " + move + " Alpha=>" +
                    //              alpha + " Beta=>" + beta + " Depth: " + depth + "\n";

                    //if (child.gs.GetBoardScore(Initial_Gs.WhoseMove) < alpha- 10)
                    //    continue;

                    

                    //iterate
                    var nodeValue = Iterate(child, depth - 1, alpha, beta, false, indent);

                    if (nodeValue > alpha)
                    {
                        alpha = nodeValue;
                        if (node == rootNode || bestNode == null)
                            bestNode = child;
                    }

                    if (beta < alpha)
                    {
                        break;
                    }
                }

                return alpha;
            }
            else
            {
                //indent
                //indent += " ";

                foreach (Node child in childs)
                {
                    //logging
                    //double score = child.gs.GetBoardScore(Initial_Gs.WhoseMove);
                    //string move = "";
                    //if (child.currentMi != null)
                    //    move = child.currentMi.WriteFullMove();
                    //else
                    //    move = child.ogMove.WriteFullMove();
                    //treeVisual += indent + "\\-B " + score + " => Move: " + move + " Alpha=>" + alpha + " Beta=>" +
                    //              beta + " Depth: " + depth + "\n";


                    beta = Math.Min(beta, Iterate(child, depth - 1, alpha, beta, true,indent));

                    if (beta < alpha)
                    {
                        break;
                    }
                }

                return beta;
            }
        }
    }
}